package com.piece.core.pay.client.impl;

import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.pay.client.AbstractPayClient;
import com.piece.core.pay.client.PayClient;
import com.piece.core.pay.client.PayClientConfig;
import com.piece.core.pay.client.PayClientFactory;
import com.piece.core.pay.client.impl.alipay.*;
import com.piece.core.pay.client.impl.wxpay.WXNativePayClient;
import com.piece.core.pay.client.impl.wxpay.WXPayClientConfig;
import com.piece.core.pay.client.impl.wxpay.WXJsPayClient;
import com.piece.core.pay.enums.PayChannelType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * 支付客户端的工厂实现类
 */
@Slf4j
public class PayClientFactoryImpl implements PayClientFactory {

    /**
     * 支付客户端集合
     */
    private final ConcurrentMap<String, AbstractPayClient<?>> clients = new ConcurrentHashMap<>();

    @Override
    public PayClient getPayClient(String channelId, String channelCode) {
        AbstractPayClient<?> client = clients.get(channelId + ":" + channelCode);
        if (null == client) {
            log.error("[支付渠道编号({}) 找不到客户端]", channelId);
            throw new RuntimeException(I18nUtil.message(ExceptionConstants.NOT_EXIST, "支付渠道(" + channelId + ")客户端"));
        }
        return client;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Config extends PayClientConfig> void initPayClient(String channelId, String channelCode, Config config) {
        AbstractPayClient<Config> client = (AbstractPayClient<Config>) clients.get(channelId + ":" + channelCode);
        if (null == client) {
            client = this.createPayClient(channelId, channelCode, config);
            client.init();
            clients.put(channelId + ":" + channelCode, client);
        } else {
            client.refresh(config);
        }
    }

    @SuppressWarnings("unchecked")
    private <Config extends PayClientConfig> AbstractPayClient<Config> createPayClient(
            String channelId, String channelCode, Config config) {
        PayChannelType channelEnum = PayChannelType.getByCode(channelCode);
        Assert.notNull(channelEnum, String.format("支付渠道(%s) 为空", channelEnum));
        // 创建客户端
        switch (channelEnum) {
            case WX_PUB:
            case WX_LITE:
            case WX_APP: return (AbstractPayClient<Config>) new WXJsPayClient(channelId, (WXPayClientConfig) config);
            case WX_NATIVE: return (AbstractPayClient<Config>) new WXNativePayClient(channelId, (WXPayClientConfig) config);
            case ALIPAY_PC: return (AbstractPayClient<Config>) new AliPayPcPayClient(channelId, (AliPayClientConfig) config);
            case ALIPAY_WAP: return (AbstractPayClient<Config>) new AliPayWapPayClient(channelId, (AliPayClientConfig) config);
            case ALIPAY_QR: return (AbstractPayClient<Config>) new AliPayQrPayClient(channelId, (AliPayClientConfig) config);
            case ALIPAY_APP: return (AbstractPayClient<Config>) new AliPayAppPayClient(channelId, (AliPayClientConfig) config);
        }

        log.error("找不到合适的[{}]支付客户端实现", config);
        throw new IllegalArgumentException(I18nUtil.message(ExceptionConstants.NOT_EXIST, String.format("配置(%s)客户端实现", config)));
    }

    @Override
    public void removePayClient(String channelId) {
        List<String> keys = clients.keySet().stream().map(key -> {
            if (key.startsWith(channelId)) {
                return key;
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(keys)) {
            keys.stream().forEach(key -> clients.remove(channelId));
        }
    }
}
